/**
 *    Copyright 2012 Geensoft S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
package ar.com.greensoft.neo.service.impl;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.richfaces.application.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import ar.com.greensoft.neo.dao.DaoException;
import ar.com.greensoft.neo.dao.GroupDao;
import ar.com.greensoft.neo.dao.GroupMemberDao;
import ar.com.greensoft.neo.dao.PaisDao;
import ar.com.greensoft.neo.dao.ProvinciaDao;
import ar.com.greensoft.neo.model.Group;
import ar.com.greensoft.neo.model.GroupAuthorities;
import ar.com.greensoft.neo.model.GroupMember;
import ar.com.greensoft.neo.model.MenuAccess;
import ar.com.greensoft.neo.model.Pais;
import ar.com.greensoft.neo.model.Provincia;
import ar.com.greensoft.neo.model.User;
import ar.com.greensoft.neo.model.references.ISO3166_1;
import ar.com.greensoft.neo.service.UserService;
import ar.com.greensoft.neo.util.ApplicationGroups;
import ar.com.greensoft.neo.util.ApplicationRoles;
import ar.com.greensoft.neo.web.jsf.beans.common.ApplicationMenu;

/**
 * Aqui&acute; hay que colocar todas las inserciones por defecto que debe tener cargada la
 * BBDD antes de iniciar la aplicaci&oacute;n.
 * @author Jorge E. Villaverde
 * @version 1.0.0
 * @since 07/02/2012
 */
@Service
@Scope(value="singleton")
public class InicializationServiceImp implements ApplicationGroups {
	private static final Logger logger = LoggerFactory.getLogger(InicializationServiceImp.class);

	private static final String ADMIN_USER = "admin";
	
	private static String[] provinciasArgentinas = {
		"Capital Federal",
		"Buenos Aires",
		"Catamarca",
		"Chaco",
		"Chubut",
		"Córdoba",
		"Corrientes",
		"Entre Ríos",
		"Formosa",
		"Jujuy",
		"La Pampa",
		"La Rioja",
		"Mendoza",
		"Misiones",
		"Neuquén",
		"Río Negro",
		"Salta",
		"San Juan",
		"San Luis",
		"Santa Cruz",
		"Santa Fe",
		"Santiago del Estero",
		"Tierra del Fuego",
		"Tucumán"		
	};
	
	@Autowired
	private PaisDao paisDao;
	@Autowired
	private ProvinciaDao provinciaDao;
	@Autowired
	private UserService userService;
	@Autowired
	private GroupDao groupDao;
	@Autowired
	private GroupMemberDao groupMemberDao;
	
	@Autowired
	private List<ApplicationMenu> userMenues;
	
	@PostConstruct
	public void initServices(){
		logger.info("INITIALIZING Services...");
		
		chechDefaultGroups();
		chechDefaultUsers();
		checkPaises(); 
		checkProvincias();    	
		
		logger.info("INITIALIZING Services: COMPLETE");
	}


	private void chechDefaultGroups() {
		checkGroup(GROUP_ADMINISTRATORS);
	}

	private void checkGroup(String groupName) {
		boolean found = false;
		List<Group> groups = null;
		try {
			groups = groupDao.findByName(groupName);
			if(groups.size() > 0){
				for(Group group : groups){
					if(groupName.equals(group.getName())){
						found = true;
						break;
					}
				}						
			}
		} catch (DaoException e) {
			logger.error(e.getMessage());
		}
		
		if(!found)
			createGroup(groupName);
	}


	private void createGroup(String groupName) {
		Group group = new Group();
		group.setName(groupName);
				
		try {
			groupDao.persist(group);
			
			if(GROUP_ADMINISTRATORS.equals(groupName)){
				int menuSequence = 0;
				for(ApplicationMenu am : userMenues){
					MenuAccess ma = new MenuAccess();
					ma.setGroup(group);
					ma.setMenuSequence(menuSequence++);
					ma.setName(am.getMenuName());
					group.getMenuAccess().add(ma);
				}
				groupDao.merge(group);

				for(ApplicationRoles role : ApplicationRoles.values()){
					GroupAuthorities ga = new GroupAuthorities();
					ga.setGroup(group);
					ga.setAuthority(role.name());
					groupDao.addAuthority(ga);
					group.getAuthorities().add(ga);
				}
			}			
		} catch (DaoException e) {
			logger.error(e.getMessage());
		}
	}

	private void chechDefaultUsers() {
		try {
			User user = userService.findUserByUsername(ADMIN_USER);
			if(user == null){
				logger.info("Admin User Not Found, creating default user");
				user = userService.createUser(ADMIN_USER, ADMIN_USER);

				List<Group> groupsAdmin = groupDao.findByName(GROUP_ADMINISTRATORS);
				
				for(Group group : groupsAdmin){
					GroupMember gm = new GroupMember();
					gm.setGroup(group);
					gm.setUser(user);
					groupMemberDao.persist(gm);
				}
			}
		} catch (ServiceException e) {
			logger.error(e.getMessage());
		} catch (DaoException e) {
			logger.error(e.getMessage());
		}		
	}


	private void checkProvincias() {
		try {
			Pais pais = paisDao.findByCode(ISO3166_1.AR);
			List<Provincia> listProvArgentina = provinciaDao.findByPais(pais);
			
			for(String provincia : provinciasArgentinas){
				Provincia prov = buscarProvinciaNombre(listProvArgentina, provincia);
				if(prov == null){
					logger.info("Provincia: " + provincia + "\tNOT FOUND");
					prov = new Provincia();
					prov.setPais(pais);
					prov.setName(provincia);
					provinciaDao.persist(prov);
					logger.info("Provincia: " + provincia + "\tCREATED");
				}else{
					logger.info("Provincia: " + provincia + "\tFOUND");				
				}
			}
		} catch (DaoException e) {
			logger.error(e.getMessage());
		}
	}

	private void checkPaises() {
		for(ISO3166_1 codigoISO: ISO3166_1.values()) {
			try {
				Pais pais = paisDao.findByCode(codigoISO);
				if(pais != null)
					logger.info("Pais: " + codigoISO.toString() + "\tFOUND");
				else{
					logger.info("Pais: " + codigoISO.toString() + "\tNOT FOUND");
					pais = new Pais();
					pais.setCodigoISO(codigoISO);
					pais.setName(codigoISO.getLabel());
					paisDao.persist(pais);
					logger.info("Pais: " + codigoISO.toString() + "\tCREATED");
				}
			} catch (DaoException e) {
				logger.error("Error: " + e.getMessage());
			}
			
		}		
	}

	private static Provincia buscarProvinciaNombre(List<Provincia> list, String provincia) {
		for(Provincia prov : list){
			if(provincia.equals(prov.getName()))
				return prov;
		}
		return null;
	}
	
	@PreDestroy
	public void destroyServices(){
		logger.info("DESTROYING Diputación Services...");
	}
}
